﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DualChannelProject;
using FlyCapture2Managed;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Diagnostics;
using System.Threading;
using System.Runtime.Serialization;
using CUDA;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.IO;
using BitmapApp;

using DualChannel_v2._0;
using MicroLESA;


namespace DualChannel_v2._0
{
    public partial class MainForm : Form
    {

        public PTGreyCameraControl camera1 = new PTGreyCameraControl();
        public PTGreyCameraControl camera2 = new PTGreyCameraControl();
        MatcherForm Matcherform = new MatcherForm();
        public bool Rendering = false;
        FPSMeter FPS = new FPSMeter();
        BitmapApp.Program bitpr = new BitmapApp.Program();
        VideoMode videomode = VideoMode.None;
        Bitmap Camera1Bmp;
        Bitmap Camera2Bmp;
        MicroLESAForm Lesa = new MicroLESAForm();

        Bitmap[] MachineGunBW = new Bitmap[4];
        Bitmap[] MachineGunColor = new Bitmap[4];
        Bitmap[] MachineGunOverlay = new Bitmap[4];
        int currBulletBW = 0, currBulletOverlay = 0, currBulletColor = 0;
        bool AffineMatrixReady = false;
        byte bwTrashold = 15;
        Thread OverlayThread;
        ManualResetEvent OverlayThreadHandle = new ManualResetEvent(false);
        bool ColorAdd = false;
        bool NormalizationOnRed = false;
        private double brightness = 1;
        byte[] Gamma = new byte[256];
        double Level = 0.1;
        CustomColor FluorColor = CustomColor.FromColor(Color.Fuchsia);

        int BulletBW
        {
            get { return (currBulletBW == 0) ? 3 : currBulletBW - 1; }
        }
        int BulletColor
        {
            get { return (currBulletColor == 0) ? 3 : currBulletColor - 1; }
        }
        int BulletOverlay
        {
            get { return (currBulletOverlay == 0) ? 3 : currBulletOverlay - 1; }
        }

        public MainForm()
        {
            InitializeComponent();
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            SavePicBrawserDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures);
            CUDAProcessing.InitHW();

            OverlayThread = new Thread(OverlayWork);
            OverlayThread.Priority = ThreadPriority.Highest;

            #region CameraInitialization
            camera1.Invert = BWHorFlip.Checked;
            camera2.Invert = ColorHorFlip.Checked;
            camera1.UpdatePic = new PTGreyCameraControl.UpdatePicDel(UpdatePicCam1);
            camera2.UpdatePic = new PTGreyCameraControl.UpdatePicDel(UpdatePicCam2);

            try
            {
                ManagedBusManager busMgr = new ManagedBusManager();
                uint numCameras = busMgr.GetNumOfCameras();

                if (numCameras >= 2)
                {
                    Console.WriteLine("Number of cameras detected: {0}", numCameras);


                    //HAS TO BE CHANGED TO CAM ID BASED MODE
                    ManagedPGRGuid guid = busMgr.GetCameraFromIndex(0);
                    if (busMgr.GetInterfaceTypeFromGuid(guid) == InterfaceType.Ieee1394 || busMgr.GetInterfaceTypeFromGuid(guid) == InterfaceType.GigE)
                    {
                        camera1.InitCameraWithGuid(guid);
                        camera2.InitCameraWithGuid(busMgr.GetCameraFromIndex(1));
                    }
                    else
                    {
                        camera2.InitCameraWithGuid(guid);
                        camera1.InitCameraWithGuid(busMgr.GetCameraFromIndex(1));
                    }
					camera1.camThread.Name = "BW camera";
					camera2.camThread.Name = "Color camera";
                    camera1.camThread.Priority = ThreadPriority.Normal;
                    camera2.camThread.Priority = ThreadPriority.Normal;
				}
                else
                {
                    MessageBox.Show("Обнаружена только одна камера.");
                    return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            #region LoadPreferences

            try
            {

                ManagedCameraBase mb = camera1.m_camera as ManagedCameraBase;

                //mb.StopCapture();
                Format7ImageSettings f7 = new Format7ImageSettings();
                uint pack = 0;
                float speed = 0;
                //mb.GetFormat7Configuration(f7, ref pack, ref speed);
                //f7.mode = Mode.Mode1;
                //mb.SetFormat7Configuration(f7, 100);

                CameraProperty cp = mb.GetProperty(PropertyType.FrameRate);
                cp.absControl = true;
                cp.absValue = 30;
                cp.autoManualMode = false;
                mb.SetProperty(cp);
                //mb.StartCapture();


                ManagedCamera mc = camera2.m_camera as ManagedCamera;
                mb = camera2.m_camera as ManagedCameraBase;
                //mb.StopCapture();
                f7 = new Format7ImageSettings();
                pack = 0;
                speed = 0;

                //mc.GetFormat7Configuration(f7, ref pack, ref speed);
                //f7.pixelFormat = PixelFormat.PixelFormatRgb;

                cp = mb.GetProperty(PropertyType.FrameRate);
                cp.absValue = 30;

                mb.SetProperty(cp);

                //f7.mode = Mode.Mode4;
                //mb.SetFormat7Configuration(f7, 100);

                cp = mb.GetProperty(PropertyType.FrameRate);
                cp.absControl = true;
                cp.absValue = 30;
                cp.autoManualMode = false;
                mb.SetProperty(cp);
                FC2Config cf = mb.GetConfiguration();

                //SavebleCameraProperty[] BWProperties = new SavebleCameraProperty[18];
                //SavebleCameraProperty[] ColorProperties = new SavebleCameraProperty[18];
                //for (int i = 0; i < 18; i++)
                //    BWProperties[i] = new SavebleCameraProperty((camera1.m_camera as ManagedCameraBase).GetProperty((PropertyType)i));
                //for (int i = 0; i < 18; i++)
                //    ColorProperties[i] = new SavebleCameraProperty((camera2.m_camera as ManagedCameraBase).GetProperty((PropertyType)(i - 18)));

                //SaveConfig sc = new SaveConfig();
                //sc.BWCamProperties = BWProperties;
                //sc.ColorCamProperties = ColorProperties;

                ////Макс! Зачем он спрашивает каждый раз?
                //DialogResult dr = System.Windows.Forms.DialogResult.None; //affinematrixsaveFileDialog1.ShowDialog();

                //dr = affinematrixsaveFileDialog1.ShowDialog();
                //if (dr == System.Windows.Forms.DialogResult.OK)
                //{
                //    BinaryFormatter bf = new BinaryFormatter();
                //    bf.Serialize(new FileStream(affinematrixsaveFileDialog1.FileName, FileMode.Create), sc);
                //} 
            





                //Console.WriteLine(((PropertyType)i).ToString() + mb.GetProperty((PropertyType)i).absValue.ToString());
                //mb.StartCapture();
                cf = mb.GetConfiguration();
            }
            catch (Exception ex) { Console.WriteLine(ex.Message); }
            #endregion
            #endregion

            #region MachineGunsInit
            for (int i = 0; i < MachineGunBW.Length; i++)
                MachineGunBW[i] = new Bitmap(camera1.Width, camera1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            for (int i = 0; i < MachineGunColor.Length; i++)
                MachineGunColor[i] = new Bitmap(camera1.Width, camera1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            for (int i = 0; i < MachineGunOverlay.Length; i++)
                MachineGunOverlay[i] = new Bitmap(camera1.Width, camera1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            #endregion


            try
            {
                BinaryFormatter bf = new BinaryFormatter();
                Matcherform.AffineMatrix = bf.Deserialize(new FileStream(Application.StartupPath + "\\AffineMatrix.afm", FileMode.Open)) as Matrix<float>;
                AffineMatrixReady = true;
                Matcherform.MartixViewUpdate();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading Affine Matrix: " + ex.Message);
            }

            //StartOverlayMode();
            LoadDefaultSettings();
        }

        bool DXInited = false;
        void InitDXWorker(Size picSize)
        {
            pictureBox.Size = picSize;
            bitpr.PrepareToRun(new SharpDX.Samples.DemoConfiguration("", picSize.Width, picSize.Height), pictureBox);
            cropImageToolStripMenuItem_CheckedChanged(new object(), new EventArgs());
            FPS.Start();
            DXInited = true;
        }
        void DisposeDXWorker()
        {
            bitpr.StopRender = true;
            Rendering = false;
            bitpr.EndRun();
            bitpr.BitmapToDraw = null;
            bitpr.m_processedImage = null;
            bitpr.Dispose();
        }
        void StartDx()
        {
            bitpr.StopRender = false;
            Rendering = true;
            bitpr.BeginRun();
            bitpr.RunRenderLoop(pictureBox);
        }
        void StopDx()
        {
            bitpr.StopRender = true;
            Rendering = false;
            bitpr.EndRun();
        }

        private void runBW_btn_Click(object sender, EventArgs e)
        {
            if (videomode != VideoMode.BWMode)
            {
                if (OverlayThread.ThreadState == System.Threading.ThreadState.Running) OverlayThreadHandle.Reset(); 
                if (camera2.camThread.ThreadState == System.Threading.ThreadState.Running) camera2.StopCapture();
                if (camera1.camThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin) camera1.StartCapture();
                //TODO Restart BW Thread

                if (Rendering) StopDx();
                Thread.Sleep(100);
                if (bitpr.m_processedImage == null)
                {
                    bitpr.m_processedImage = camera1.m_rawImage;
                    bitpr.BitmapToDraw = bitpr.m_processedImage.bitmap;
                }
                videomode = VideoMode.BWMode;
                GC.Collect();
                if (!DXInited) InitDXWorker(camera1.ImageSize);
                if (!Rendering) StartDx();
            }
        }
        private void runColor_btn_Click(object sender, EventArgs e)
        {
            if (videomode != VideoMode.ColorMode)
            {

                if (OverlayThread.ThreadState == System.Threading.ThreadState.Running) OverlayThreadHandle.Reset(); 
                if (camera1.camThread.ThreadState == System.Threading.ThreadState.Running) camera1.StopCapture();
                if (camera2.camThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin) camera2.StartCapture();
                //TODO Restart Color Thread

                if (Rendering) StopDx();
                Thread.Sleep(100);
                if (bitpr.m_processedImage == null)
                {
                    bitpr.m_processedImage = camera2.m_rawImage;
                    bitpr.BitmapToDraw = bitpr.m_processedImage.bitmap;
                }
                videomode = VideoMode.ColorMode;
                GC.Collect();
                if (!DXInited) InitDXWorker(camera2.ImageSize);
                if (!Rendering) StartDx();
            }
        }
        private void overlay_btn_Click(object sender, EventArgs e)
        {
            if (videomode != VideoMode.OverlayMode)
            {
                if (camera1.camThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin) camera1.StartCapture();
                if (camera2.camThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin) camera2.StartCapture();
                if (Rendering) StopDx();
                if (bitpr.m_processedImage == null)
                {
                    bitpr.m_processedImage = camera2.m_rawImage;
                    bitpr.BitmapToDraw = bitpr.m_processedImage.bitmap;
                }
                videomode = VideoMode.OverlayMode;
                GC.Collect();
                if (OverlayThread.ThreadState == System.Threading.ThreadState.Unstarted) { OverlayThread.Start(OverlayThreadHandle); Thread.Sleep(1000); }
                if (OverlayThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin) OverlayThreadHandle.Set();
                if (!DXInited) InitDXWorker(camera2.ImageSize);
                if (!Rendering) StartDx();
            }
        }

        

        int GlobalCounter = 0;
        void OverlayWork(object st)
        {
            CUDAProcessing.InitHW();
            ManualResetEvent MRE = (ManualResetEvent)st;
            //Bitmap TomatoGunBW = null, TomatoGunColor = null;
            while (true)

            {
                MRE.WaitOne();
                //try
                //{
                //    if (TomatoGunBW == MachineGunBW[BulletBW] && TomatoGunColor == MachineGunColor[BulletColor])
                //        continue;
                //}
                //catch { }
                ////Index was outside the bounds of the array.
                //TomatoGunBW = MachineGunBW[BulletBW];
                //TomatoGunColor = MachineGunColor[BulletColor];
                ////Index was outside the bounds of the array.
                Camera1Bmp = (Bitmap)MachineGunBW[BulletBW].Clone();
                Camera2Bmp = (Bitmap)MachineGunColor[BulletColor].Clone();

                double GainShutter = 1;
                GainShutter = camera2.LastGain * camera2.LastShutter / camera1.LastGain / camera1.LastShutter;
                if (double.IsInfinity(GainShutter) || double.IsNaN(GainShutter)) GainShutter = 1;
                GainShutter *= 2550;

                
                
                Bitmap resBmp = (Bitmap)CUDAProcessing.UploadBitmap
                    (
                    Camera1Bmp,
                    Camera2Bmp,
                    AffineMatrixReady,
                    Matcherform.AffineMatrixInverse,
                    NormalizationOnRed,
                    GainShutter,
                    bwTrashold,
                    ColorAdd,
                    Gamma,
                    brightness,
                    Level,
                    FluorColor,
                    CoeffRectPosition,
                    CoeffRectSide
                    ).Clone();

                //MachineGunOverlay[currBulletOverlay] = resBmp;
                //currBulletOverlay++;
                //currBulletOverlay %= 4;

				#region ResBitmapDrawing
                if (double.IsNaN(CurrentCursorValue) || double.IsInfinity(CurrentCursorValue))
                    CurrentCursorValue = CUDAProcessing.IF[0];
                CurrentCursorValue = CurrentCursorValue / 8.0 * 7.0 + CUDAProcessing.IF[0] / 8.0;

                bitpr.Text = (CurrentCursorValue / CalibrationValue).ToString("F1");

                bitpr.LesaBitmap = null;
                if (Lesa != null)
                    if (LESACheck.Checked && Lesa.LesaBitmap != null)
                    {
                        bitpr.LesaBitmap = Lesa.LesaBitmap;
                        bitpr.LesaText = Lesa.LesaText;
                    }

                bitpr.BitmapToDraw = resBmp;// MachineGunOverlay[BulletOverlay];

                GlobalCounter++;

                FPS.Update();
                
                MachineGunOverlay[currBulletOverlay] = resBmp;
                currBulletOverlay = (currBulletOverlay + 1) % 4;

                //Todo убрать очистку коллектора путем создания метода переворачивания картинки
                #endregion
                GC.Collect();
            }
        }

        private void ZoomAndPlacedPictureBox(float scale)
        {
            int d = Math.Max(splitContainer1.Panel1.Width, splitContainer1.Panel1.Height);
            int f = Math.Min(splitContainer1.Panel1.Width, splitContainer1.Panel1.Height);
            Size picSize = new Size();
            if (splitContainer1.Panel1.Width == d)
                if (f * scale >= d)
                {
                    picSize.Width = d;
                    picSize.Height = (int)(d / scale);
                }
                else
                {
                    picSize.Width = (int)(f * scale);
                    picSize.Height = f;
                }
            else { picSize.Height = (int)(f / scale); picSize.Width = f; }
            pictureBox.Size = picSize;
            pictureBox.Location = new Point((splitContainer1.Panel1.Width - picSize.Width) / 2, (splitContainer1.Panel1.Height - picSize.Height) / 2);
        }

        private void splitContainer1_Panel1_SizeChanged(object sender, EventArgs e)
        {
            if (Matcherform.CropRectShape.Visible) ZoomAndPlacedPictureBox(Matcherform.CropRectangle.Width / Matcherform.CropRectangle.Height);
            else ZoomAndPlacedPictureBox(4f / 3f);
        }
        
		private void UpdatePicCam1(Bitmap bmp)
        {
            if (videomode == VideoMode.BWMode)
            {
                bitpr.BitmapToDraw = bmp;
                FPS.Update();
                GlobalCounter++;
            }
            if (videomode == VideoMode.OverlayMode)
            {
                MachineGunBW[currBulletBW] = bmp;
                currBulletBW = (currBulletBW + 1) % 4;
            };
        }
		private void UpdatePicCam2(Bitmap bmp)
        {
            if (videomode == VideoMode.ColorMode)
            {
                bitpr.BitmapToDraw = bmp;
                FPS.Update();
                GlobalCounter++;
            }
            if (videomode == VideoMode.OverlayMode)
            {
                MachineGunColor[currBulletColor] = bmp;
                currBulletColor = (currBulletColor + 1) % 4;
            }
            GC.Collect();
         }
        

        enum VideoMode { BWMode, ColorMode, OverlayMode, None }
        private void tunemathcer_menuitem_Click(object sender, EventArgs e)
        {
            if (OverlayThread.ThreadState == System.Threading.ThreadState.Running) OverlayThreadHandle.Reset();
            try
            {
                if (camera1.OutImage == null) {camera1.StartCapture(); Thread.Sleep(100);} 
                if (camera2.OutImage == null) {camera2.StartCapture(); Thread.Sleep(100);}
                camera1.StopCapture();
                camera2.StopCapture();
                Thread.Sleep(10);

                camera1.RWSLock.EnterReadLock();
                Matcherform.BWimage = new Image<Bgr, byte>((Bitmap)camera1.OutImage.Clone());
                camera1.RWSLock.ExitReadLock();
                camera2.RWSLock.EnterReadLock();
                Matcherform.Cimage = new Image<Bgr, byte>((Bitmap)camera2.OutImage.Clone());
                camera2.RWSLock.ExitReadLock();

                //TODO Костыль - слип 300. Иначе бывает ошибка поломанной памяти при ShowDialog
                //Вылетает когда драйвер камеры начинает чудить. (Не изменяет частоту работы камеры). Спасает извлечение шнурка из юсб.
                //Thread.Sleep(300);
                //Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
                GC.Collect();
                DialogResult dr = Matcherform.ShowDialog(); 
                if (dr == System.Windows.Forms.DialogResult.OK)
                {
                    AffineMatrixReady = true;
                    if (Matcherform.CropRectangle.Size != bitpr.sourceArea.Size && cropImageToolStripMenuItem.Checked) CropChanged();
                }
                switch (videomode)
                {
                    case VideoMode.BWMode:camera1.StartCapture();
                        break;
                    case VideoMode.ColorMode:camera2.StartCapture();
                        break;
                    case VideoMode.OverlayMode:
                        camera1.StartCapture();
                        camera2.StartCapture();
                        OverlayThreadHandle.Set();
                        break;
                    case VideoMode.None:
                        break;
                }
                camera1.StartCapture();
                camera2.StartCapture();
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void addColorToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            ColorAdd = addColorToolStripMenuItem.Checked;
        }
        private void normBWonRedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NormalizationOnRed = normBWonRedToolStripMenuItem.Checked;
        }
        private void selectColortoolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DialogResult dr = colorDialog1.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
                FluorColor = CustomColor.FromColor(colorDialog1.Color);
        }

        private void Brightness_Scroll(object sender, EventArgs e)
        {
            bwTrashold = (byte)BWTrasholdtb.Value;
        }
        private void Brightness_ValueChanged(object sender, EventArgs e)
        {
            brightness = Brightness.Value / 10.0;
            for (int i = 0; i < 256; i++)
                Gamma[i] = (byte)(1 / Math.Pow(256, 1 / brightness) * 255 * Math.Pow(i, 1 / brightness));
        }
        private void levertrb_ValueChanged(object sender, EventArgs e)
        {
            Level = levertrb.Value / (double)100;
        }

        private void saveastoolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (AffineMatrixReady)
            {
                DialogResult dr = affinematrixsaveFileDialog1.ShowDialog();
                if (dr == System.Windows.Forms.DialogResult.OK)
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(new FileStream(affinematrixsaveFileDialog1.FileName, FileMode.Create), Matcherform.AffineMatrix);
                }
            }
        }
        private void saveAffineMatrixToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (AffineMatrixReady)
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(new FileStream(Application.StartupPath + "\\AffineMatrix.afm", FileMode.Create), Matcherform.AffineMatrix);
            }
        }
        private void loadAffineMatrixToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dr = affinematrixopenFileDialog1.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                AffineMatrixReady = false;
                BinaryFormatter bf = new BinaryFormatter();
                Matcherform.AffineMatrix = (Matrix<float>)bf.Deserialize(new FileStream(affinematrixopenFileDialog1.FileName, FileMode.Open));
                Matcherform.MartixViewUpdate();
                AffineMatrixReady = true;
            }
        }

        private void bWCameraToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool rend = Rendering;
            //if (Rendering) StopDx();
            camera1.ShowDialog();
            
            //videomode = VideoMode.None;
            //if (!DXInited) InitDXWorker(camera1.ImageSize);
            //if (rend) StartDx();
        }
        private void colorCameraToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool rend = Rendering;
            //if (Rendering) StopDx();
            camera2.ShowDialog();
            //if (!DXInited) InitDXWorker(camera1.ImageSize);
            //if (rend) StartDx();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            FPSMeter.Text = "FPS=" + GlobalCounter.ToString();
            GlobalCounter = 0;
        }


        double CalibrationValue = 1;
        double CurrentCursorValue = double.NaN;
        string SavePicFolder { get { return SavePicBrawserDialog.SelectedPath; } }


        private void calibrate_btn_Click(object sender, EventArgs e)
        {
            if (!double.IsNaN(CurrentCursorValue))
                CalibrationValue = CurrentCursorValue;
        }
        private void save_on_pan_btn_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(SavePicFolder);
            if (!backgroundPicSaver.IsBusy)
                backgroundPicSaver.RunWorkerAsync(SavePicFolder);
        }
        private void save_btn_Click(object sender, EventArgs e)
        {
            DialogResult dr = SavePicBrawserDialog.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                bitpr.SaveCapture(SavePicBrawserDialog.SelectedPath + "\\WorkBench.bmp");
            }
        }
        private void folder2save_btn_Click(object sender, EventArgs e)
        {
            SavePicBrawserDialog.ShowDialog();
        }

        private void backgroundPicSaver_DoWork(object sender, DoWorkEventArgs e)
        {
            string Folder = e.Argument as string;
            string FileTemplate = Folder + string.Format("\\{0}_{1}_{2}_{3}_{4}_{5}_{6}",
                DateTime.Now.Year,
                DateTime.Now.Month,
                DateTime.Now.Day,
                DateTime.Now.Hour,
                DateTime.Now.Minute,
                DateTime.Now.Second,
                DateTime.Now.Millisecond);

            try
            {
                MachineGunBW[currBulletBW].Save(FileTemplate + "_BW.BMP");
            }
            catch { }

            try
            {
                MachineGunColor[currBulletColor].Save(FileTemplate + "_Color.BMP");
            }
            catch { }

            //try
            // {
            bitpr.BitmapToSave = (Bitmap)MachineGunOverlay[currBulletOverlay].Clone();
            bitpr.SaveCapture(FileTemplate + "_Overlay.bmp");
            // }
            //catch{ }
            GC.Collect();
        }

        private void MainForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.F2)
            {
                save_btn_Click(sender, e);
            }
        }

        private void BWHorFlip_CheckedChanged(object sender, EventArgs e)
        {
            camera1.Invert = BWHorFlip.Checked;
        }
        private void ColorHorFlip_CheckedChanged(object sender, EventArgs e)
        {
            camera2.Invert = ColorHorFlip.Checked;
        }
        private void perferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dr = colorDialog2.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
                bitpr.UpdateConcentrationFontColor(colorDialog2.Color);
        }
        private void cropImageToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            if (cropImageToolStripMenuItem.Checked)
            {
                if (Matcherform.CropRectShape.Visible) CropChanged();
                else 
                { 
                    //MessageBox.Show("Не выбрана область обрезания.\nПопробуйте Tools\\Matcher\\Tune\\Crop"); 
                    cropImageToolStripMenuItem.CheckState = CheckState.Unchecked; 
                }
            }
            else
            {
                bitpr.sourceArea = new Rectangle(0, 0, camera2.ImageSize.Width, camera2.ImageSize.Height);
                bitpr.SourceAreaChanged();
                ZoomAndPlacedPictureBox(4f / 3f);
            }
            CoeffRectangleChanged();
        }
        private void CropChanged()
        {
            bitpr.sourceArea = Matcherform.CropRectangle;
            bitpr.SourceAreaChanged();
            ZoomAndPlacedPictureBox((float)Matcherform.CropRectangle.Width / Matcherform.CropRectangle.Height);
        }
        
        Point CoeffRectPosition;
        int CoeffRectSide = 10;

        private void CoeffRectangleChanged()
        {
            
            Rectangle crop = Matcherform.CropRectangle;
            if (Matcherform.CropRectShape.Visible) CoeffRectPosition = new Point(crop.Left + crop.Width / 2 - CoeffRectSide, crop.Top + crop.Height / 2 - CoeffRectSide);
            else CoeffRectPosition = new Point(camera1.ImageSize.Width / 2 - CoeffRectSide, camera1.ImageSize.Height / 2 - CoeffRectSide);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (Lesa == null)
                Lesa = new MicroLESAForm();
            Lesa.Show();

        }

        private void LESACheck_CheckedChanged(object sender, EventArgs e)
        {
            if (LESACheck.Checked)
            {
                if (Lesa == null)
                {
                    Lesa = new MicroLESAForm();
                    Lesa.Show();
                    Application.DoEvents();
                    Lesa.Hide();
                }
                Lesa.Start();
            }
        }

        private void flipImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bitpr.FlipY180 = flipImagepMenuItem.Checked;
        }
        
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer1.Enabled = false;
            DisposeDXWorker();
            OverlayThread.Abort();
            Thread.Sleep(100);
            camera1.StopCapture();
            camera1.camThread.Abort();
            camera2.StopCapture();
            camera2.camThread.Abort();
        }
        private void quit_Click(object sender, EventArgs e)
        {
           Application.Exit();
 	    }
        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            quit_Click(sender, e);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            DialogResult dr = affinematrixsaveFileDialog1.ShowDialog();
            if (dr != System.Windows.Forms.DialogResult.OK)
                return;
            string FileName = affinematrixsaveFileDialog1.FileName;

            SaveSettingsToXML(FileName);

        }

        private void SaveSettingsToXML(string FileName)
        {
            //Camera settings
            SaveConfig sc = GenerateSaveConfig();



            SoapFormatter bf = new SoapFormatter();
            bf.Serialize(new FileStream(FileName, FileMode.Create), sc);
        }



        private SaveConfig GenerateSaveConfig()
        {
            SavebleCameraProperty[] BWProperties = new SavebleCameraProperty[18];
            SavebleCameraProperty[] ColorProperties = new SavebleCameraProperty[18];
            for (int i = 0; i < 18; i++)
                BWProperties[i] = new SavebleCameraProperty((camera1.m_camera as ManagedCameraBase).GetProperty((PropertyType)i));
            for (int i = 0; i < 18; i++)
                ColorProperties[i] = new SavebleCameraProperty((camera2.m_camera as ManagedCameraBase).GetProperty((PropertyType)(i)));

            CameraPropertyInfo cpi = camera1.m_camera.GetPropertyInfo(BWProperties[0].type);
            

            SaveConfig sc = new SaveConfig();
            sc.BWCamProperties = BWProperties;
            sc.ColorCamProperties = ColorProperties;

            sc.BWCamID = camera1.m_camera.GetCameraInfo().serialNumber;
            sc.ColorCamID = camera2.m_camera.GetCameraInfo().serialNumber;

            //Main settings
            sc.Trashold = BWTrasholdtb.Value;
            sc.Brightness = Brightness.Value;
            sc.Sensitivity = levertrb.Value;
            sc.FluorColor = FluorColor.GetColor();
            sc.DigitColor = bitpr.GetConcentrationColor();

            //LESA settings
            sc.LesaM1 = (int)Lesa.numericUpDown1.Value;
            sc.LesaM2 = (int)Lesa.numericUpDown2.Value;
            sc.LesaM3 = (int)Lesa.numericUpDown3.Value;
            sc.LesaM4 = (int)Lesa.numericUpDown4.Value;
            sc.LesaCropFrom = (int)Lesa.TrimFrom.Value;
            sc.LesaCropTo = (int)Lesa.TrimTo.Value;
            sc.LesaA = Lesa.A;
            sc.LesaB = Lesa.B;
            sc.LesaWidth = Lesa.Width;
            sc.LesaHeight = Lesa.Height;
            sc.LesaDispersion = (double)Lesa.Dispersion.Value;
            sc.LaserWL = (double)Lesa.PeakWL.Value;
            return sc;
        }

        private void button4_Click(object sender, EventArgs e)
        {

            DialogResult dr = affinematrixopenFileDialog1.ShowDialog();
            if (dr != System.Windows.Forms.DialogResult.OK)
                return;

            string FileName = affinematrixopenFileDialog1.FileName;

            LoadSettingsFromXML(FileName);


        }

        private void LoadSettingsFromXML(string FileName)
        {
            SaveConfig sc;
            SoapFormatter bf = new SoapFormatter();
            sc = (SaveConfig)bf.Deserialize(new FileStream(FileName, FileMode.Open));

            //Camera settings
            for (int i = 0; i < 18; i++)
                if (sc.BWCamProperties[i].present)
                    (camera1.m_camera as ManagedCameraBase).SetProperty(sc.BWCamProperties[i].CloneToCamedraProperty());

            for (int i = 0; i < 18; i++)
                if (sc.ColorCamProperties[i].present)
                    (camera2.m_camera as ManagedCameraBase).SetProperty(sc.ColorCamProperties[i].CloneToCamedraProperty());

            //General Settings
            //Main settings
            BWTrasholdtb.Value = sc.Trashold;
            Brightness.Value = sc.Brightness;
            levertrb.Value = sc.Sensitivity;

            FluorColor = CustomColor.FromColor(sc.FluorColor);
            //bitpr.UpdateConcentrationFontColor(sc.DigitColor);

            //LESA settings
            Lesa.numericUpDown1.Value = sc.LesaM1;
            Lesa.numericUpDown2.Value = sc.LesaM2;
            Lesa.numericUpDown3.Value = sc.LesaM3;
            Lesa.numericUpDown4.Value = sc.LesaM4;
            Lesa.TrimFrom.Value = sc.LesaCropFrom;
            Lesa.TrimTo.Value = sc.LesaCropTo;
            Lesa.A = sc.LesaA;
            Lesa.B = sc.LesaB;
            Lesa.Width = sc.LesaWidth;
            Lesa.Height = sc.LesaHeight;
            Lesa.Dispersion.Value = (decimal)sc.LesaDispersion;
            Lesa.PeakWL.Value = (decimal)sc.LaserWL;
        }

        private void saveDefaultSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string FileName = Application.StartupPath + "\\DefaultConfig.XML";
            try
            {
                SaveSettingsToXML(FileName);
            }
            catch
            {
                MessageBox.Show("Error saving default configuration");
            }
        }

        private void saveSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog sd = new SaveFileDialog();
            sd.Title = "Enter config file name";
            sd.DefaultExt = "XML";
            sd.Filter = "XML files|*.xml|All files|*.*";
            sd.InitialDirectory = Application.StartupPath;

            DialogResult dr = sd.ShowDialog();
            if (dr != System.Windows.Forms.DialogResult.OK)
                return;
            string FileName = sd.FileName;
              try
            {
            SaveSettingsToXML(FileName);
            }
              catch
              {
                  MessageBox.Show("Error saving configuration");
              }
        }

        private void loadDefaultSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadDefaultSettings();
        }

        private void LoadDefaultSettings()
        {
            string FileName = Application.StartupPath + "\\DefaultConfig.XML";
            try
            {
                LoadSettingsFromXML(FileName);
            }
            catch
            {
                MessageBox.Show("Error loading default configuration");
            }
        }

        private void loadSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog sd = new OpenFileDialog();
            sd.Title = "Enter config file name";
            sd.DefaultExt = "XML";
            sd.Filter = "XML files|*.xml|All files|*.*";
            sd.InitialDirectory = Application.StartupPath;

            DialogResult dr = sd.ShowDialog();
            if (dr != System.Windows.Forms.DialogResult.OK)
                return;
            string FileName = sd.FileName;
            try
            {
                LoadSettingsFromXML(FileName);
            }
            catch
            {
                MessageBox.Show("Error loading configuration");
            }
        }

        CameraControlForm CamControl = new CameraControlForm();

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            if (CamControl.Camera == camera1.m_camera)
                CamControl.Visible = !CamControl.Visible;
            else CamControl.Show();
            CamControl.Populate(camera1.m_camera);

        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            if (CamControl.Camera == camera2.m_camera)
                CamControl.Visible = !CamControl.Visible;
            else CamControl.Show();
            CamControl.Populate(camera2.m_camera);

        }

        private void quitToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            quit_Click(sender, e);
        }
        tets TestWindow;
        private void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                Rectangle crop = Matcherform.CropRectangle;
                float dimscale = (Matcherform.CropRectShape.Visible && cropImageToolStripMenuItem.Checked) ? (float)pictureBox.Width / Matcherform.CropRectangle.Width : (float)pictureBox.Width / camera1.Width;

                if (Matcherform.CropRectShape.Visible && cropImageToolStripMenuItem.Checked)
                {
                    CoeffRectPosition.X = (e.X / dimscale + crop.Left - CoeffRectSide > crop.Left) ? (int)(e.X / dimscale + crop.Left - CoeffRectSide) : crop.Left;
                    CoeffRectPosition.Y = (e.Y / dimscale+crop.Top - CoeffRectSide > crop.Top) ? (int)(e.Y / dimscale+crop.Top - CoeffRectSide) : crop.Top;
                    CoeffRectPosition.X = (e.X / dimscale + crop.Left + CoeffRectSide > crop.Right) ? (int)(crop.Right - 2 * CoeffRectSide - 1) : CoeffRectPosition.X;
                    CoeffRectPosition.Y = (e.Y / dimscale+crop.Top + CoeffRectSide > crop.Bottom) ? (int)(crop.Bottom -2* CoeffRectSide-1) : CoeffRectPosition.Y;
                }
                else
                {
                    CoeffRectPosition.X = (e.X / dimscale - CoeffRectSide > 0) ? (int)(e.X / dimscale - CoeffRectSide) : 0;
                    CoeffRectPosition.Y = (e.Y / dimscale - CoeffRectSide > 0) ? (int)(e.Y / dimscale - CoeffRectSide) : 0;
                    CoeffRectPosition.X = (e.X / dimscale + CoeffRectSide > camera1.Width) ? (int)(camera1.Width - 2 * CoeffRectSide - 1) : CoeffRectPosition.X;
                    CoeffRectPosition.Y = (e.Y / dimscale + CoeffRectSide > camera1.Height) ? (int)(camera1.Height - 2 * CoeffRectSide - 1) : CoeffRectPosition.Y;
                }
            }
        }

        private void toolStripLabel1_Click(object sender, EventArgs e)
        {
            StopDx();
        }
    }


    [Serializable]
    public class SCameraProperty
    {
        public SCameraProperty(CameraProperty c)
        {

            absControl = c.absControl;
            absValue = c.absValue;
            autoManualMode = c.autoManualMode;
            onePush = c.onePush;
            onOff = c.onOff;
            present = c.present;
            type = (int)c.type;
            valueA = c.valueA;
            valueB = c.valueB; 
        }

        public CameraProperty Generate()
        {
            CameraProperty c = new CameraProperty();

            c.absControl = absControl;
            c.absValue = absValue;
            c.autoManualMode = autoManualMode;
            c.onePush = onePush;
            c.onOff = onOff;
            c.present = present;
            c.type = (PropertyType)type;
            c.valueA = valueA;
            c.valueB = valueB;

            return c;
        }

        public bool absControl; 
        public float absValue; 
        public bool autoManualMode; 
        public bool onePush; 
        public bool onOff; 
        public bool present;
        public int type;
        public uint valueA; 
        public uint valueB; 
    }

    [Serializable]
    public class SaveConfig
    {
        //Cameras settings
        public SavebleCameraProperty[] BWCamProperties;
        public SavebleCameraProperty[] ColorCamProperties;
        public uint BWCamID { get; set; }
        public uint ColorCamID { get; set; }

        //Main settings
        public int Trashold { get; set; }
        public int Brightness { get; set; }
        public int Sensitivity { get; set; }
        public Color FluorColor { get; set; }
        public Color DigitColor { get; set; }

        //LESA settings
        public int LesaM1 { get; set; }
        public int LesaM2 { get; set; }
        public int LesaM3 { get; set; }
        public int LesaM4 { get; set; }
        public int LesaCropFrom { get; set; }
        public int LesaCropTo { get; set; }
        public double LesaA { get; set; }
        public double LesaB { get; set; }
        public int LesaWidth { get; set; }
        public int LesaHeight { get; set; }
        public double LesaDispersion { get; set; }
        public double LaserWL { get; set; }
    }




    public class CustomColor
    {
        public float R = 0, G = 0, B = 0;

        public static CustomColor FromColor(Color color)
        {
            CustomColor cc = new CustomColor();
            cc.B = (float)color.B / 255f;
            cc.G = (float)color.G / 255f;
            cc.R = (float)color.R / 255f;
            return cc;
        }

        public Color GetColor()
        {
            return Color.FromArgb((int)(R * 255f), (int)(G * 255f), (int)(B * 255f));
        }
    }



    class FPSMeter : Stopwatch
    {
        double lastUpdateFps = 0;
        double FrameCounter = 0;
        double FrameAccum = 0;
        double FPS = 0;
        public double GetFPS()
        {
            if (FrameAccum >= 0.20f)
            {
                FPS = FrameCounter / FrameAccum;
                FrameAccum = 0.0f;
                FrameCounter = 0;
            };
            return (FPS);
        }
        public void Update()
        {
            FrameCounter++;
            FrameAccum += (this.ElapsedTicks * 0.0000001 - lastUpdateFps);
            lastUpdateFps = this.ElapsedTicks * 0.0000001;
        }
    }

    [Serializable()]
    public class SavebleCameraProperty
    {
        //public SavebleCameraProperty();
        //public SavebleCameraProperty(PropertyType type);
        public SavebleCameraProperty(CameraProperty cp)
        {
            absControl = cp.absControl;
            absValue = cp.absValue;
            autoManualMode = cp.autoManualMode;
            onePush = cp.onePush;
            onOff = cp.onOff;
            present = cp.present;
            type = cp.type;
            valueA = cp.valueA;
            valueB = cp.valueB;
        }
        public CameraProperty CloneToCamedraProperty()
        {
            CameraProperty cp = new CameraProperty();

            cp.absControl = absControl;
            cp.absValue = absValue;
            cp.autoManualMode = autoManualMode;
            cp.onePush = onePush;
            cp.onOff = onOff;
            cp.present = present;
            cp.type = type;
            cp.valueA = valueA;
            cp.valueB = valueB;

            return cp;
        }

        public bool absControl { get; set; }
        public float absValue { get; set; }
        public bool autoManualMode { get; set; }
        public bool onePush { get; set; }
        public bool onOff { get; set; }
        public bool present { get; set; }
        public PropertyType type { get; set; }
        public uint valueA { get; set; }
        public uint valueB { get; set; }
    }
}
